package com.young.launch_task_init.core.dispatcher

import com.young.launch_task_init.core.Constant
import com.young.launch_task_init.core.InitManager
import com.young.launch_task_init.core.group.BaseTaskGroup
import com.young.launch_task_init.core.group.LazyInitTaskGroup
import com.young.launch_task_init.core.group.MustInitTaskGroup
import com.young.launch_task_init.core.listener.OnCompletedListener
import com.young.launch_task_init.core.log.ILog
import com.young.launch_task_init.core.task.AsynTask
import com.young.launch_task_init.core.task.SyncTask
import com.young.launch_task_init.core.task.base.ITask
import com.young.launch_task_init.core.util.PrintTestInfoUtil
import kotlinx.coroutines.*
import kotlin.system.measureTimeMillis

/**
 * Author：young
 * .
 * Time： 1/4/2023 上午1:51 周六
 * .
 * Desc：默认的任务调度器
 */
class DefaultTaskDispatcher : ITaskDispatcher {
    // 初始化任务管理器
    private lateinit var manager: InitManager

    // 协程作用域
    private lateinit var coroutineScope: CoroutineScope

    // 打印测试信息工具类
    private val printTestInfoUtil by lazy {
        PrintTestInfoUtil()
    }

    override suspend fun dispatchTasks(
        coroutineScope: CoroutineScope,
        taskGroupList: List<BaseTaskGroup<*>>,
        manager: InitManager
    ) {
        this.coroutineScope = coroutineScope
        this.manager = manager

        // 必须初始化任务组的集合获取 job
        val mustTaskJob = coroutineScope.async {
            taskGroupList.filterIsInstance<MustInitTaskGroup>()
        }

        // 懒加载初始化任务组集合的获取 job
        val lazyTaskJob = coroutineScope.async {
            taskGroupList.filterIsInstance<LazyInitTaskGroup>()
        }

        // 必须初始化任务组的集合
        val mustTaskGroupList = mustTaskJob.await()

        // 懒加载初始化的任务组集合
        val lazyTaskGroupList = lazyTaskJob.await()

        // 分发执行必须初始化任务组
        doDispatchTaskGroups(mustTaskGroupList, manager.onCompletedListener)
        // 分发执行懒加载任务组
        doDispatchTaskGroups(lazyTaskGroupList, manager.onLazyCompletedListener)

    }

    /**
     * 分发执行任务组
     *
     * @param taskGroupList 任务组集合
     * @param onCompletedListener 任务执行完成监听
     *
     */
    private suspend fun doDispatchTaskGroups(
        taskGroupList: List<BaseTaskGroup<*>>,
        onCompletedListener: OnCompletedListener?
    ) {
        if (taskGroupList.isEmpty()) {
            // 任务组集合是空的，直接完成
            if (isShowLog()) {
                if (onCompletedListener != null) {
                    getLog().logE(Constant.LOG_TAG, "任务组是空的，所以标记完成")
                }
            }
            onCompletedListener?.let { listener ->
                withContext(Dispatchers.Main) {
                    listener.onCompleted(0)
                    printTestInfoUtil.printAllTaskComplete(0)
                }
            }
            return
        }


        // 总的任务个数
        val totalTaskSize = taskGroupList.sumOf {
            it.getTaskList().size
        }

        if (totalTaskSize == 0) {
            // 总的任务个数是0，直接完成
            if (isShowLog()) {
                if (onCompletedListener != null) {
                    getLog().logE(Constant.LOG_TAG, "任务组拥有的任务集合是空的，所以标记完成")
                }
            }
            onCompletedListener?.let { listener ->
                withContext(Dispatchers.Main) {
                    listener.onCompleted(0)
                    if (isShowLog()) {
                        printTestInfoUtil.printAllTaskComplete(0)
                    }
                }
            }
            return
        }

        // 计算任务的执行耗时
        val time = measureTimeMillis {
            doDispatchTasks(taskGroupList, onCompletedListener, totalTaskSize)
        }


        // 所有任务执行完成
        onCompletedListener?.let { listener ->
            withContext(Dispatchers.Main) {
                listener.onCompleted(time)
                if (isShowLog()) {
                    printTestInfoUtil.printAllTaskComplete(time)
                }
            }
        }

    }

    /**
     * 分发任务组执行任务
     *
     * @param taskGroupList 任务组集合
     * @param onCompletedListener 任务执行完成监听
     * @param totalTaskSize 总的任务个数
     *
     */
    private suspend fun doDispatchTasks(
        taskGroupList: List<BaseTaskGroup<*>>,
        onCompletedListener: OnCompletedListener?,
        totalTaskSize: Int
    ) {
        // 总的任务完成个数
        var totalProgress = 0
        // 组的个数
        val groupSize = taskGroupList.size

        for ((index, group) in taskGroupList.withIndex()) {

            // 如果任务列表是空的，则继续下轮循环
            if (group.isEmpty()) {
                continue
            }

            // 协程任务
            val jobs = getTaskJobs(group)

            // 任务个数
            val taskSize = jobs.size
            // 等待协程任务结束
            for ((index1, job) in jobs.withIndex()) {
                // 等待任务完成
                val task = job.await()
                // 切换到主线程进行回调
                withContext(Dispatchers.Main) {
                    // 每个任务完成回调
                    onCompletedListener?.onCompletedPerTask(task, index1 + 1, taskSize)

                    // 总的任务进度
                    totalProgress += 1
                    // 总的任务进度回调
                    onCompletedListener?.onTotalCompleted(
                        task,
                        group,
                        totalProgress,
                        totalTaskSize
                    )

                    if (isShowLog()) {
                        printTestInfoUtil.printPerTaskGroupCompletedProgress(
                            group,
                            task,
                            index1 + 1,
                            taskSize
                        )
                        printTestInfoUtil.printTotalCompletedProgress(
                            task,
                            group,
                            totalProgress,
                            totalTaskSize
                        )
                    }
                }
            }

            if (onCompletedListener != null) {
                withContext(Dispatchers.Main) {
                    // 完成每一组
                    onCompletedListener.onCompletedPerGroup(group, index + 1, groupSize)

                    if (isShowLog()) {
                        printTestInfoUtil.printTaskGroupCompletedProgress(
                            group,
                            index + 1,
                            groupSize
                        )
                    }

                }

            }

        }
    }

    /**
     * 执行任务并且获取执行的协程 job 集合
     *
     * @param group 任务组
     */
    private fun getTaskJobs(group: BaseTaskGroup<*>): List<Deferred<ITask>> {

        // 需要执行的任务集合
        val taskList = group.getTaskList()

        // 协程任务
        val jobs = mutableListOf<Deferred<ITask>>()

        // 遍历执行任务
        for (task in taskList) {
            if (task is AsynTask) {
                // 异步初始化任务
                coroutineScope.async(task.getCoroutineDispatcher()) {
                    if (isShowLog()) {
                        printTestInfoUtil.printTaskDoOnThread(group, task)
                    }

                    task.doTask(manager.application)
                }
                // 这里的等待任务使用 CountDown，所以在异步线程等待
                jobs.add(coroutineScope.async {
                    task.isComplete()
                    task
                })
            } else if (task is SyncTask) {
                // 同步任务
                jobs.add(coroutineScope.async(task.getCoroutineDispatcher()) {
                    if (isShowLog()) {
                        printTestInfoUtil.printTaskDoOnThread(group, task)
                    }
                    task.doTask(manager.application)
                    task.isComplete()
                    task
                })
            } else {
                try {
                    throw ClassCastException(
                        "[${task::class.java.name}] 必须继承 ${AsynTask::class.java.name} " +
                                "或 ${SyncTask::class.java.name} "
                    )
                } catch (e: Exception) {
                    if (isShowLog()) {
                        getLog().logE(
                            Constant.LOG_TAG,
                            "*发生异常：${e::class.java.name} ${e.localizedMessage}"
                        )
                    }
                    throw e
                }
            }
        }

        return jobs
    }


    /**
     * 获取日志输出类
     */
    private fun getLog(): ILog {
        return manager.log
    }

    /**
     * 是否展示日志
     */
    private fun isShowLog(): Boolean {
        return manager.isShowLog
    }
}